﻿#include "widget.h"
#include "./ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    ,client(new QTcpSocket(this))
    ,server(new QTcpServer(this))
    ,Udpsocket(new QUdpSocket(this))
    ,retryTimer(new QTimer(this))
    ,isbutton(false)//true 按下;false 未按下
    ,open_down(false)
{
    ui->setupUi(this);
    sta=notconnect;
    statusjudge(sta);
    Init(ui->comboBox->currentText());//初始化界面，隐藏不必要项
    ui->sendtextEdit->setText("Hello world");

    if(ui->comboBox->currentText()=="TCP Client"){
        retryTimer->setSingleShot(true); // 单次触发
        connect(retryTimer, &QTimer::timeout, this, [=](){       
            if(sta!=connectting)
            {
                retryTimer->stop();
                return;
            }
            retryTimer->stop(); // 停止之前的定时器
            retryTimer->start(10000);
            myto_connect(client);
        });
    }

    connect(ui->comboBox, &QComboBox::currentTextChanged,
            this, &Widget::onIndexChanged);//切换协议类型进入槽函数
    connect(ui->clearDataButton,&QPushButton::clicked,this,&Widget::clearDataSlot);//清空数据日志
    connect(ui->clearSendButton,&QPushButton::clicked,this,&Widget::clearSendSlot);//清空发送区
    connect(ui->connectButton,&QPushButton::clicked,this,&Widget::to_connectSlot);
    connect(ui->sendButton,&QPushButton::clicked,this,&Widget::senddataSlot);
}


Widget::~Widget()
{
    delete ui;
    retryTimer->stop();
    if (client) {
        client->disconnectFromHost();
        client->deleteLater();
    }
    if (server) {
        server->close();
        server->deleteLater();
    }
}

//切换协议类型改变界面
void Widget::onIndexChanged(const QString &text){
    Init(text);
}


//连接按钮槽函数
void Widget::to_connectSlot(void){
    if(ui->comboBox->currentText()=="TCP Client")
    {
        isbutton=true;
        if(ui->addresslineEdit->text().isEmpty())
        {
            QMessageBox::information(this,"提示","无效的主机地址");
        }
        else if(ui->portlineEdit->text().isEmpty()||ui->portlineEdit->text().toInt()==0)
        {
            QMessageBox::information(this,"提示","无效的远程主机端口");
        }else{
            if(sta==success){
                client->close();
                sta=notconnect;
                retryTimer->stop();
            }else if(sta==notconnect){
                myto_connect(client);
                sta=connectting;
                retryTimer->stop();
                retryTimer->start(10000);
            }else if(sta==connectting)
            {
                sta=notconnect;
                ui->datatextEdit->append("停止重试");
            }
            statusjudge(sta);
            isbutton=false;
        }//else
    }else
    {
        if(open_down==true)
        {
            if(ui->comboBox->currentText()=="TCP Server")
            {
                server->close();
                server->deleteLater();
                server = nullptr;
            }else if(ui->comboBox->currentText()=="UDP")
            {
                Udpsocket->close();
                Udpsocket->deleteLater();
                Udpsocket=nullptr;
            }
            open_down=false;
            open_or_down(open_down);
        }
        else
        {
            if(ui->portlineEdit->text().toInt()<65535&&ui->portlineEdit->text().toInt()>0)
            {
                QStringList localAddrs = getLocalIPv4Address();
                QHostAddress addr(ui->addresslineEdit->text());
                if ((localAddrs.contains(ui->addresslineEdit->text()))||
                    (addr.isLoopback() ||addr == QHostAddress(QHostAddress::AnyIPv4)))
                {
                    open_down=true;
                    open_or_down(open_down);//设置状态为打开
                    ui->addresslineEdit->setText(ui->addresslineEdit->text());
                    if(ui->comboBox->currentText()=="TCP Server")
                    {
                        if (server) {
                            server->close();
                            server->deleteLater();
                            server = nullptr;
                        }
                        server=new QTcpServer(this);
                        server->listen(QHostAddress(ui->addresslineEdit->text()),ui->portlineEdit->text().toInt());//监听

                        connect(server,&QTcpServer::newConnection,this,[=]()
                                {
                                    QTcpSocket* socket = server->nextPendingConnection();
                                    myThread* t = new myThread(socket);
                                    Widget::connect(t,&myThread::dataReady,this,&Widget::serverRecvdata);
                                    Widget::connect(this,&Widget::sendsignal,t,&myThread::senddata_to);
                                    connect(t, &myThread::finished, t, &QObject::deleteLater);

                                    connect(t, &myThread::disconnected, this, [this](myThread* thread) {

                                    });

                                    QThreadPool::globalInstance()->start(t);
                                });
                    }else if(ui->comboBox->currentText()=="UDP")
                    {
                        if (Udpsocket) {
                            Udpsocket->close();
                            Udpsocket->deleteLater();
                            Udpsocket = nullptr;
                        }
                        qint16 port=ui->portlineEdit->text().toInt();
                        Udpsocket=new QUdpSocket(this);
                        if(!Udpsocket->bind(QHostAddress::AnyIPv4,port))
                        {
                            QMessageBox::critical(this, "错误", QString("绑定失败: %1").arg(Udpsocket->errorString()));
                            open_down = false;
                            Udpsocket->deleteLater();
                            Udpsocket = nullptr;
                            return;
                        }
                        connect(Udpsocket,&QUdpSocket::readyRead,this,&Widget::acceptudpslot);
                        open_down = true;
                    }
                }
                else
                {
                    QMessageBox::information(this,"提示","无效的ip地址");
                }
            }else{
                QMessageBox::information(this,"提示","无效的端口号");
            }
        }
    }
}//to_connectSlot end

void Widget::acceptudpslot()
{
    qDebug()<<"收到数据了";
    qint64 size = Udpsocket->pendingDatagramSize();
    if (size == -1) {
        // 没有待读取的数据
        return;
    }
    // 使用QByteArray来存储数据
    QByteArray datagram;
    datagram.resize(size);

    QHostAddress sender;
    quint16 senderPort;

    // 读取数据报
    Udpsocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);

    // 显示接收到的数据
    ui->datatextEdit->append(QString("从 %1:%2 接收到: %3")
                                 .arg(sender.toString())
                                 .arg(senderPort)
                                 .arg(QString(datagram)));
}

void Widget::serverRecvdata(QByteArray recvdata)
{
    ui->datatextEdit->append(recvdata);
}

//寻找本地ipv4地址
QStringList Widget::getLocalIPv4Address(void) {

    QStringList addresses;
    addresses << "127.0.0.1" << "0.0.0.0"; // 预置特殊地址

    // 获取所有网络接口地址
    foreach (const QHostAddress &addr, QNetworkInterface::allAddresses()) {
        if (addr.protocol() == QAbstractSocket::IPv4Protocol &&
            !addr.isLoopback()) {
            addresses << addr.toString();
        }
    }
    return addresses;
}
//客户端连接服务器函数
void Widget::myto_connect(QTcpSocket *socket)
{
    disconnect(socket, &QTcpSocket::connected, this, nullptr);
    disconnect(socket, &QTcpSocket::errorOccurred, this, nullptr);
    disconnect(socket, &QTcpSocket::disconnected, this, nullptr);
    disconnect(socket, &QTcpSocket::readyRead, this, &Widget::recvdataSlot);

    socket->abort();
    QString IP=ui->addresslineEdit->text();
    QString port=ui->portlineEdit->text();

    socket->connectToHost(QHostAddress(IP),port.toShort());
    connect(socket, &QTcpSocket::readyRead, this, &Widget::recvdataSlot);
    //连接成功
    connect(socket,&QTcpSocket::connected,this,[=]()
            {
                sta=success;
                retryTimer->stop();
                statusjudge(sta); // 统一状态管理

            });
    //连接出错
    connect(socket, &QTcpSocket::errorOccurred, this, [=](QAbstractSocket::SocketError error)
            {
                if(sta!=connectting)return;
                retryTimer->stop(); // 停止之前的定时器
                ui->datatextEdit->append("连接超时,10秒后重试");
                retryTimer->start(10000);  // 10秒后触发重试
            });
    //连接断开，socket会发出信号
    connect(socket,&QTcpSocket::disconnected,this,[=]()
            {
                if(isbutton==true)
                {
                    ui->datatextEdit->append("连接断开");
                }
                else{
                    sta=connectting;
                    statusjudge(sta);
                    retryTimer->start(10000);
                    ui->datatextEdit->append("连接断开，十秒后重新连接");
                }
            });
}

//服务器状态判断函数
void Widget::open_or_down(bool od)
{
    if(od==true)
    {
        ui->connectButton->setText("关闭");
        ui->addresslineEdit->setReadOnly(1);
        ui->portlineEdit->setReadOnly(1);
        ui->comboBox->setEnabled(false);
        ui->addresslineEdit->setStyleSheet("QLineEdit { color: gray; } QLineEdit:disabled { background-color: gray; }");
        ui->portlineEdit->setStyleSheet("QLineEdit { color: gray; } QLineEdit:disabled { background-color: gray; }");
        if(ui->comboBox->currentText()=="UDP")
        {
            ui->UDPlabel->setVisible(1);
            ui->UDPlineEdit->setVisible(1);
        }
    }
    else
    {
        ui->connectButton->setText("打开");
        ui->addresslineEdit->setReadOnly(0);
        ui->portlineEdit->setReadOnly(0);
        ui->comboBox->setEnabled(true);
        ui->addresslineEdit->setStyleSheet("QLineEdit { color: black; } QLineEdit:disabled { background-color: black; }");
        ui->portlineEdit->setStyleSheet("QLineEdit { color: black; } QLineEdit:disabled { background-color: black; }");
    }
}

//客户端状态判断函数-》用于调整连接按钮显示
void Widget::statusjudge(Widget::connectStatus sta) {
    if (sta == Widget::notconnect) {
        ui->addresslineEdit->setReadOnly(0);
        ui->addresslineEdit->setStyleSheet("QLineEdit { color: black; } QLineEdit:disabled { background-color: black; }");
        ui->portlineEdit->setStyleSheet("QLineEdit { color: black; } QLineEdit:disabled { background-color: black; }");
        ui->portlineEdit->setReadOnly(0);
        ui->comboBox->setEnabled(true);
        ui->connectButton->setText("连接");
    } else if (sta == Widget::success) {
        ui->connectButton->setText("关闭");
        ui->addresslineEdit->setReadOnly(1);
        ui->portlineEdit->setReadOnly(1);
        ui->comboBox->setEnabled(false);
        ui->datatextEdit->append("连接成功");
    } else if (sta == Widget::connectting) {
        ui->addresslineEdit->setReadOnly(1);
        ui->addresslineEdit->setStyleSheet("QLineEdit { color: gray; } QLineEdit:disabled { background-color: gray; }");
        ui->portlineEdit->setStyleSheet("QLineEdit { color: gray; } QLineEdit:disabled { background-color: gray; }");
        ui->portlineEdit->setReadOnly(1);
        ui->comboBox->setEnabled(false);
        ui->connectButton->setText("正在连接");
        }
}

//接受数据槽函数
void Widget::recvdataSlot(void){
    Readdata(client);
}

//发送数据槽函数
void Widget::senddataSlot(void){

    if(ui->comboBox->currentText()=="TCP Client")
    {
        Writedata(client);
    }
    else if(ui->comboBox->currentText()=="TCP Server")
    {
        QByteArray array=ui->sendtextEdit->toPlainText().toUtf8();
        emit sendsignal(array);
    }
    else if(ui->comboBox->currentText()=="UDP")
    {
        if (!Udpsocket) {
            QMessageBox::information(this, "错误", "UDP未初始化或绑定失败");
            return;
        }
        if(!ui->UDPlineEdit->text().isEmpty())
        {
            if(ui->UDPlineEdit->text().contains(":"))
            {
                QStringList parts = ui->UDPlineEdit->text().split(":");
                QString ip = parts[0];
                QString port = parts[1];
                Udpsocket->writeDatagram(ui->sendtextEdit->toPlainText().toUtf8(),QHostAddress(ip),port.toInt());
            }else
            {
                QStringList mylist=getLocalIPv4Address();
                QMessageBox::information(this,"提示","无法解析\n请输入如下格式:\n例如 "+mylist[mylist.size()-1]+":8080");
            }
        }
    }
}

//写数据函数
void Widget::Writedata(QTcpSocket *socket){
    QByteArray sendData=ui->sendtextEdit->toPlainText().toUtf8();
    socket->write(sendData);
}

//读数据函数
void Widget::Readdata(QTcpSocket *socket){
    QTcpSocket *psocket=qobject_cast<QTcpSocket *>(sender());
    QByteArray readData=psocket->readAll();
    ui->datatextEdit->append(readData);
}

//界面初始化函数
void Widget::Init(QString option){

    ui->UDPlabel->setVisible(0);
    ui->UDPlineEdit->setVisible(0);
    if(option=="TCP Client")//当协议类型为TCP Client时执行
    {
        ui->portlabel->setText("*远程主机端口");
        ui->addresslabel->setText("*远程主机地址");
        ui->connectButton->setText("连接");

    }
    else{
        ui->portlabel->setText("*本地主机端口");
        ui->addresslabel->setText("*本地主机地址");
        ui->connectButton->setText("打开");
        QStringList mylist=getLocalIPv4Address();
        ui->addresslineEdit->setText(mylist[mylist.size()-1]);
    }

}

//清空发送区
void Widget::clearSendSlot(void){
    ui->sendtextEdit->clear();
}

//清空数据日志
void Widget::clearDataSlot(void)
{
    ui->datatextEdit->clear();
}
